package org.afei.ioc.factory;

import org.afei.ioc.annotation.Bean;
import org.afei.ioc.data.DataContext;
import org.afei.ioc.entity.BeanEntity;
import org.afei.ioc.handler.HandlerDecorator;
import org.afei.ioc.util.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 具体的服务工厂，实现了处理服务的算法
 *
 * @author afei
 * @date 17-5-25.
 */
public class DefaultBeanFactory extends
        AbstractBeanFactory {

    private static final Logger LOGGER =
            LoggerFactory.getLogger(DefaultBeanFactory.class);

    @Override
    public void setHandler(String defaultHandler, String handlerName) {
        LOGGER.info("-------------注册处理元数据的Handler-----------");
        handlerDecorator = (HandlerDecorator) ReflectionUtil.getInstance(defaultHandler);
        if (handlerName != null) {
            HandlerDecorator newHandler = (HandlerDecorator) ReflectionUtil.getInstance(handlerName);
            handlerDecorator.setHandler(newHandler);
        }
    }

    @Override
    public void setBeanDefinitionContext(String beanDefinitionContextName, String resource) {
        LOGGER.info("-------------注册服务定义信息的存储区-----------");
        beanDefinitionContext = (DataContext) ReflectionUtil.getInstance(beanDefinitionContextName);

        LOGGER.info("-------------使用Handler将元数据转换为服务定义信息-----------");
        Map<String, Object> BeanDataMap = handlerDecorator.convert(resource);

        LOGGER.info("-------------保存服务定义信息-----------");
        beanDefinitionContext.initData(BeanDataMap);
    }

    @Override
    public BeanEntity getBeanDefinition(String name) {
        LOGGER.info("-------------获取" + name + "的服务定义信息-----------");
        return (BeanEntity) beanDefinitionContext.get(name);
    }

    @Override
    public boolean containsBeanCache(String name) {
        LOGGER.info("-------------判断服务提供者" + name + "是否有缓存-----------");
        return beanCacheContext.get(name) != null;
    }

    @Override
    public Object getBeanCache(String name) {
        LOGGER.info("-------------从缓存中获取服务提供者" + name + "-----------");
        return beanCacheContext.get(name);
    }

    @Override
    public <T> T getBeanCache(String name, Class<T> clazz) {
        return beanCacheContext.get(name, clazz);
    }

    @Override
    //递归调用，获取注入Bean依赖的Bean
    public Object creatBean(BeanEntity beanEntity) {

        LOGGER.info("-------------根据服务定义信息创建服务提供者" + beanEntity.getName() + "-----------");
        Object obj = ReflectionUtil.getInstance(beanEntity.getType());
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            Bean bean = field.getAnnotation(Bean.class);
            if (bean == null) {
                continue;
            }
            field.setAccessible(true);
            try {
                field.set(obj, getBean(bean.name()));
            } catch (Exception e) {

            }
        }

        return obj;
    }

    @Override
    public <T> T creatBean(Class<T> clazz) {
        T obj = ReflectionUtil.getInstance(clazz);
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            Bean bean = field.getAnnotation(Bean.class);
            if (bean == null) {
                continue;
            }
            field.setAccessible(true);
            try {
                field.set(obj, getBean(bean.name()));
            } catch (Exception e) {

            }
        }

        return obj;
    }

    @Override
    public Object regiterBeanCache(String name, Object obj) {
        LOGGER.info("-------------将服务提供者" + name + "放入缓存区-----------");
        beanCacheContext.set(name, obj);
        return null;
    }

    @Override
    public DataContext getBeanDefinitionContext() {
        return beanDefinitionContext;
    }

    @Override
    public DataContext getBeanCacheContext() {
        return beanCacheContext;
    }

    @Override
    public void setBeanCacheContext(String beanCacheContextName) {
        LOGGER.info("-------------注册服务提供者的缓存区-----------");
        beanCacheContext = (DataContext) ReflectionUtil.getInstance(beanCacheContextName);
        beanCacheContext.initData(new HashMap<>());
    }

}
